import {
  Controller,
  Post,
  Body,
  Req,
  Get,
  UseGuards,
  Request,
  Param,
  Query,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport/dist/auth.guard';
import { JwtService } from '@nestjs/jwt';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import IP2Region from 'ip2region';
import { AuthService } from './auth.service';
import { AuthCreateDto } from './auth.create.dto';
import jwtConfig from '../../../../../config/jwt.config';
import { RedisInstance } from '../../../../../util/redis';
import { Public } from '../../../../../common/public.decorator';
import { CryptoService } from '../../../../../util/crypto';
import { userLoginList, userLoginDocument } from '../../schemas/login.schema';

@Controller('auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private jwtService: JwtService,
    @InjectModel(userLoginList.name)
    private userLoginModel: Model<userLoginDocument>,
  ) {}

  @Public()
  @Post('login')
  async login(@Body() body: AuthCreateDto, @Request() req: any) {
    let backData = {};
    try {
      const userRes = await this.authService.login(body);
      if (!userRes.data) {
        backData = userRes;
        return;
      }
      const token = await this.createToken(userRes.data);
      // 初始化 Redis 实例，用于 'auth.login' 操作，使用数据库 0
      await RedisInstance.initRedis('auth.login', 0);

      // 创建一个键，基于用户的 ID 和用户名，用于存储登录相关的信息
      const key = `${userRes.data.id}-${userRes.data.username}`;

      // 将登录令牌设置到 Redis 中，键为用户的唯一标识，值为生成的 token
      // 设置过期时间，与 jwtConfig.expiresIn 相同，确保与 JWT 的有效期同步
      await RedisInstance.setRedis(
        'auth.login',
        0,
        key,
        `${token}`,
        jwtConfig.expiresIn,
      );
      const ip = req.ip;
      const ipv4Address = this.extractIPv4(ip);
      const query = new IP2Region();
      const ipRes = query.search(ipv4Address);
      const onrRow = {
        userId: userRes.data.id,
        username: userRes.data.username,
        token: token,
        ip: ipv4Address,
        loginLocation: JSON.stringify(ipRes),
        loginType: body.loginType,
      };
      await this.userLoginModel.create(onrRow);
      backData = {
        code: 200,
        flag: true,
        data: token,
      };
    } catch (error) {
      backData = { code: 200, flag: false, msg: error };
    } finally {
      return backData;
    }
  }

  @Get('userInfoByToken')
  @UseGuards(AuthGuard('jwt')) // 使用 JWT 鉴权
  async userInfo(@Req() request: any) {
    return {
      code: 200,
      data: request.user,
      msg: 'success',
    };
  }

  @Public()
  @Get('graphicCode')
  async generateGraphicCode(@Request() req: any) {
    let ip = req.ip;
    if (ip.indexOf('::ffff:') !== -1) {
      ip = ip.substring(7);
    }
    const graphicCodeData = await this.authService.generateGraphicCode(ip);
    return {
      code: 200,
      data: graphicCodeData,
      msg: 'success',
    };
  }

  /**
   * 生成登录二维码
   * @param req
   */
  @Public()
  @Get('generateQr')
  async generateQr(@Query() query: any, @Request() req: any) {
    let ip = req.ip;
    if (ip.indexOf('::ffff:') !== -1) {
      ip = ip.substring(7);
    }
    return this.authService.generateQRCode(ip, query);
  }

  @Public()
  @Get('encrypt/:text')
  async encryption(@Param('text') text: string) {
    const cryptoService = new CryptoService();
    const encText = cryptoService.encrypt(text);
    return {
      data: {
        encText,
        text,
      },
    };
  }

  async createToken(loginUser: any) {
    const payload = {
      loginName: loginUser.username,
      password: loginUser.password,
      id: loginUser._id,
    };
    return this.jwtService.sign(payload);
  }

  extractIPv4(ip: string): string {
    const ipv4Regex = /::ffff:(\d+\.\d+\.\d+\.\d+)/;
    const match = ip.match(ipv4Regex);
    if (match) {
      return match[1];
    } else {
      return ip;
    }
  }
}
